package com.qiaoba.module.system.service.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.qiaoba.api.system.entity.dto.SysMenuDTO;
import com.qiaoba.api.system.entity.vo.RouterVO;
import com.qiaoba.api.system.entity.vo.SysMenuVO;
import com.qiaoba.common.base.constant.BaseConstant;
import com.qiaoba.common.base.exception.ServiceException;
import com.qiaoba.module.system.converter.SysMenuConverter;
import com.qiaoba.module.system.entity.SysMenu;
import com.qiaoba.module.system.entity.param.SysMenuParam;
import com.qiaoba.module.system.mapper.SysMenuMapper;
import com.qiaoba.module.system.service.SysMenuService;
import com.qiaoba.module.system.util.MenuUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 菜单 服务层实现
 *
 * @author ailanyin
 * @date 2023-09-10 12:11:59
 */
@Service
@RequiredArgsConstructor
public class SysMenuServiceImpl implements SysMenuService {

    private final SysMenuMapper sysMenuMapper;

    @Override
    public int insert(SysMenuDTO dto) {
        checkMenuNameUnique(dto.getMenuId(), dto.getParentId(), dto.getMenuName());
        return sysMenuMapper.insert(SysMenuConverter.dto2Entity(dto));
    }

    @Override
    public int updateById(SysMenuDTO dto) {
        checkMenuNameUnique(dto.getMenuId(), dto.getParentId(), dto.getMenuName());
        return sysMenuMapper.updateById(SysMenuConverter.dto2Entity(dto));
    }

    @Override
    public int deleteById(String menuId) {
        checkAllowDelete(menuId);
        return sysMenuMapper.deleteById(menuId);
    }

    @Override
    public List<SysMenu> selectList(SysMenuParam param) {
        return sysMenuMapper.selectList(SysMenuConverter.param2Wrapper((param)));
    }

    @Override
    public SysMenu selectById(String menuId, boolean allowNull) {
        SysMenu sysMenu = sysMenuMapper.selectById(menuId);
        if (!allowNull && Objects.isNull(sysMenu)) {
            throw new ServiceException(StrUtil.format("查询的菜单信息不存在, ID: {}", menuId));
        }
        return sysMenu;
    }

    @Override
    public List<SysMenuVO> selectByUserId(String userId) {
        return sysMenuMapper.selectByUserId(userId);
    }

    @Override
    public List<RouterVO> menusToRouters(List<SysMenuVO> menus) {
        List<SysMenuVO> tree = com.qiaoba.module.system.util.TreeUtil.buildTree(menus, SysMenuVO.class, "menuId", "parentId", "children");
        return MenuUtil.menusToRouters(tree);
    }

    @Override
    public List<Tree<String>> buildMenuTree(List<SysMenu> menus) {
        TreeNodeConfig config = TreeNodeConfig.DEFAULT_CONFIG.setNameKey(BaseConstant.TREE_KEY_NAME);
        return TreeUtil.build(menus, BaseConstant.DEFAULT_PARENT_ID_VALUE, config, (menu, tree) ->
                tree.setId(menu.getMenuId())
                        .setParentId(menu.getParentId())
                        .setName(menu.getMenuName())
                        .setWeight(menu.getOrderNum()));
    }

    @Override
    public List<String> selectMenuIdsByRoleId(String roleId) {
        return sysMenuMapper.selectMenuIdsByRoleId(roleId);
    }

    @Override
    public Set<String> selectPermsByUserId(String userId) {
        return sysMenuMapper.selectPermsByUserId(userId);
    }

    private void checkMenuNameUnique(String menuId, String parentId, String menuName) {
        if (StrUtil.isNotBlank(sysMenuMapper.checkMenuNameUnique(menuId, parentId, menuName))) {
            throw new ServiceException(StrUtil.format("同级已存在同名菜单: {}", menuName));
        }
    }

    private void checkAllowDelete(String menuId) {
        if (StrUtil.isNotBlank(sysMenuMapper.existChild(menuId))) {
            throw new ServiceException("存在子菜单, 不允许删除!");
        }

        String role = sysMenuMapper.existUsed(menuId);
        if (StrUtil.isNotBlank(role)) {
            throw new ServiceException(StrUtil.format("已绑定角色: {}, 请解绑后删除!", role));
        }
    }
}
